/*******************************************************************************
 * Copyright (c) Jonathan Buck - jonbuck16@gmail.com
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    jonbuck16@gmail.com - initial API and implementation
 *******************************************************************************/
package net.jonbuck.tassoo.ui.wizard.page;

import net.jonbuck.tassoo.model.Container;
import net.jonbuck.tassoo.model.Task;
import net.jonbuck.tassoo.model.provider.TassooItemProviderAdapterFactory;
import net.jonbuck.tassoo.persistence.dao.TassooDao;
import net.jonbuck.tassoo.persistence.dao.TassooDaoImpl;
import net.jonbuck.tassoo.persistence.dao.util.TassooDaoHelperUtil;
import net.jonbuck.tassoo.persistence.exception.TassooQueryException;
import net.jonbuck.tassoo.ui.util.CalendarComboWidgetValueProperty;
import net.jonbuck.tassoo.ui.util.TimeTextWidgetValueProperty;
import net.jonbuck.tassoo.ui.wizard.model.NewTaskModel;

import org.apache.commons.lang.StringUtils;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.beans.PojoObservables;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.MultiValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.wizard.WizardPageSupport;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.nebula.timetext.TimeText;
import org.eclipse.nebula.widgets.calendarcombo.CalendarCombo;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.wb.swt.SWTResourceManager;

/**
 * 
 * 
 * @since 1.0.0
 */
public class TaskDetailsPage extends WizardPage {

	private TassooDao tassooDao = TassooDaoImpl.getInstance();
	public static final String PAGE_NAME = "net.jonbuck.tassoo.wizard.page.taskdetails"; //$NON-NLS-1$
	private NewTaskModel newTaskModel;
	private Text taskName;
	private Text taskSummary;
	private CalendarCombo cmbStartDate;
	private Text txtParent;
	private Button btnSubTask;
	private Button btnSelectParent;
	private Label lblParent;
	private Combo cmbCategory;
	private Combo cmbType;
	private Combo cmbPriority;
	private TassooItemProviderAdapterFactory adapterFactory;
	private Text txtContainer;
	private Combo cmbStatus;
	private CalendarCombo cmbDueDate;
	private TimeText txtEstimatedTime;

	/**
	 * 
	 * @param pageName
	 */
	public TaskDetailsPage(String pageName, NewTaskModel newTaskModel) {
		super(pageName);
		setTitle("Create a New Task");
		setDescription("Enter the details for the new task.");
		this.newTaskModel = newTaskModel;
		adapterFactory = new TassooItemProviderAdapterFactory();
	}

	/**
	 * 
	 */
	public void createControl(Composite parent) {
		Composite container = new Composite(parent, SWT.NONE);
		GridLayout gl_container = new GridLayout();
		gl_container.verticalSpacing = 15;
		gl_container.numColumns = 2;
		gl_container.marginRight = 10;
		gl_container.marginLeft = 10;
		container.setLayout(gl_container);
		container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		setControl(container);

		Label lblTaskName = new Label(container, SWT.NONE);
		lblTaskName.setText("Task Name:");

		taskName = new Text(container, SWT.BORDER);
		taskName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));

		Label lblTaskSummary = new Label(container, SWT.NONE);
		lblTaskSummary.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
		lblTaskSummary.setText("Task Summary:");

		taskSummary = new Text(container, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
		GridData gd_taskSummary = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
		gd_taskSummary.heightHint = 40;
		taskSummary.setLayoutData(gd_taskSummary);

		Group grpParentDetails = new Group(container, SWT.NONE);
		grpParentDetails.setLayout(new GridLayout(3, false));
		grpParentDetails.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
		grpParentDetails.setText("Parent Details");

		Label lblContainer = new Label(grpParentDetails, SWT.NONE);
		lblContainer.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblContainer.setText("Container:");

		txtContainer = new Text(grpParentDetails, SWT.BORDER);
		txtContainer.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		txtContainer.setEditable(false);
		GridData gd_text = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
		gd_text.heightHint = 17;
		txtContainer.setLayoutData(gd_text);

		Button btnSelectContainer = new Button(grpParentDetails, SWT.NONE);
		btnSelectContainer.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				ElementListSelectionDialog parentContainerDialog = new ElementListSelectionDialog(Display.getDefault()
						.getActiveShell(), new AdapterFactoryLabelProvider(adapterFactory));
				parentContainerDialog.setMultipleSelection(false);
				parentContainerDialog.setMessage("Search for and Select a Conatiner");
				parentContainerDialog.setEmptyListMessage("There are no containers available");
				parentContainerDialog.setTitle("Container Selection");
				if (tassooDao.isLoaded()) {
					parentContainerDialog.setElements(tassooDao.getContainers().getContainers().toArray());
					if (parentContainerDialog.open() == IDialogConstants.OK_ID) {
						Container selectedContainer = (Container) parentContainerDialog.getFirstResult();
						if (selectedContainer != null) {
							txtContainer.setText(selectedContainer.getContainerName());
						}
					}
				}
			}
		});
		btnSelectContainer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
		btnSelectContainer.setText("Select");

		btnSubTask = new Button(grpParentDetails, SWT.CHECK);
		btnSubTask.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (btnSubTask.getSelection()) {
					lblParent.setEnabled(true);
					txtParent.setEnabled(true);
					btnSelectParent.setEnabled(true);
				} else {
					lblParent.setEnabled(false);
					txtParent.setEnabled(false);
					btnSelectParent.setEnabled(false);
				}
			}
		});
		btnSubTask.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 3, 1));
		btnSubTask.setText("Task will be a Sub Task");

		lblParent = new Label(grpParentDetails, SWT.NONE);
		lblParent.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblParent.setText("Parent:");
		lblParent.setEnabled(newTaskModel.isSubTask());

		txtParent = new Text(grpParentDetails, SWT.BORDER);
		txtParent.setEditable(false);
		txtParent.setEnabled(newTaskModel.isSubTask());
		GridData gd_txtParent = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
		gd_txtParent.heightHint = 17;
		txtParent.setLayoutData(gd_txtParent);

		btnSelectParent = new Button(grpParentDetails, SWT.NONE);
		btnSelectParent.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				ElementListSelectionDialog parentTaskDialog = new ElementListSelectionDialog(Display.getDefault().getActiveShell(),
						new AdapterFactoryLabelProvider(adapterFactory));
				parentTaskDialog.setMultipleSelection(false);
				parentTaskDialog.setMessage("Search for and Select a parent task");
				parentTaskDialog.setEmptyListMessage("There are no tasks available");
				parentTaskDialog.setTitle("Task Selection");
				if (tassooDao.isLoaded()) {
					Container container = null;
					try {
						container = TassooDaoHelperUtil.getContainerByValue(tassooDao, txtContainer.getText());
					} catch (TassooQueryException e1) {
						// TODO Handle exception correctly....
						e1.printStackTrace();
					}
					parentTaskDialog.setElements(container == null ? new Object[0] : TassooDaoHelperUtil.getActiveTasks(tassooDao,
							container));
					if (parentTaskDialog.open() == IDialogConstants.OK_ID) {
						Task task = (Task) parentTaskDialog.getFirstResult();
						txtParent.setText(task.getTaskName());
					}
				}
			}
		});
		GridData gd_btnSelectParent = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
		gd_btnSelectParent.widthHint = 80;
		btnSelectParent.setLayoutData(gd_btnSelectParent);
		btnSelectParent.setText("Select");
		btnSelectParent.setEnabled(newTaskModel.isSubTask());

		Group grpTaskProperties = new Group(container, SWT.NONE);
		grpTaskProperties.setText("Task Properties");
		GridLayout gl_grpTaskProperties = new GridLayout(2, false);
		gl_grpTaskProperties.horizontalSpacing = 20;
		gl_grpTaskProperties.marginBottom = 5;
		gl_grpTaskProperties.marginRight = 10;
		gl_grpTaskProperties.marginLeft = 10;
		grpTaskProperties.setLayout(gl_grpTaskProperties);
		grpTaskProperties.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));

		Label lblCategory = new Label(grpTaskProperties, SWT.NONE);
		lblCategory.setText("Category:");

		Label lblEstimatedTime = new Label(grpTaskProperties, SWT.NONE);
		lblEstimatedTime.setText("Start Date:");

		cmbCategory = new Combo(grpTaskProperties, SWT.NONE | SWT.READ_ONLY);
		cmbCategory.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		if (tassooDao.isLoaded()) {
			cmbCategory.setItems(TassooDaoHelperUtil.getCategoriesForCombo(tassooDao));
		}

		cmbStartDate = new CalendarCombo(grpTaskProperties, SWT.NONE | SWT.READ_ONLY);
		GridData gd_cmdStartDate = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
		gd_cmdStartDate.widthHint = 155;
		cmbStartDate.setLayoutData(gd_cmdStartDate);

		Label lblType = new Label(grpTaskProperties, SWT.NONE);
		lblType.setText("Type:");

		Label lblDueDate = new Label(grpTaskProperties, SWT.NONE);
		lblDueDate.setText("Due Date:");

		cmbType = new Combo(grpTaskProperties, SWT.NONE | SWT.READ_ONLY);
		cmbType.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		if (tassooDao.isLoaded()) {
			cmbType.setItems(TassooDaoHelperUtil.getTypesForCombo(tassooDao));
		}

		cmbDueDate = new CalendarCombo(grpTaskProperties, SWT.NONE | SWT.READ_ONLY);
		GridData gd_cmbDueDate = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
		gd_cmbDueDate.widthHint = 155;
		cmbDueDate.setLayoutData(gd_cmbDueDate);

		Label lblPriority = new Label(grpTaskProperties, SWT.NONE);
		lblPriority.setText("Priority:");

		Label lblEstimatedTime_1 = new Label(grpTaskProperties, SWT.NONE);
		lblEstimatedTime_1.setText("Estimated Time:");

		cmbPriority = new Combo(grpTaskProperties, SWT.NONE | SWT.READ_ONLY);
		cmbPriority.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		if (tassooDao.isLoaded()) {
			cmbPriority.setItems(TassooDaoHelperUtil.getPrioritiesForCombo(tassooDao));
		}

		txtEstimatedTime = new TimeText(grpTaskProperties, SWT.BORDER);
		txtEstimatedTime.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));

		Label lblStatus = new Label(grpTaskProperties, SWT.NONE);
		lblStatus.setText("Status:");
		new Label(grpTaskProperties, SWT.NONE);

		cmbStatus = new Combo(grpTaskProperties, SWT.NONE);
		cmbStatus.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		new Label(grpTaskProperties, SWT.NONE);
		if (tassooDao.isLoaded()) {
			cmbStatus.setItems(TassooDaoHelperUtil.getStatusesForCombo(tassooDao));
		}

		DataBindingContext context = initDataBindings();
		initBindingSupport(context);

		taskName.setFocus();
	}

	/**
	 * 
	 */
	private void initBindingSupport(DataBindingContext bindingContext) {
		WizardPageSupport.create(this, bindingContext);
	}

	/**
	 * 
	 * @return
	 */
	protected DataBindingContext initDataBindings() {
		DataBindingContext bindingContext = new DataBindingContext();
		//
		IObservableValue taskNameObserveTextObserveWidget = SWTObservables.observeText(taskName, SWT.Modify);
		IObservableValue newTaskModelTaskNameObserveValue = PojoObservables.observeValue(newTaskModel, "taskName");
		UpdateValueStrategy taskNameStrategy = new UpdateValueStrategy();
		taskNameStrategy.setBeforeSetValidator(new IValidator() {
			public IStatus validate(Object value) {
				if (!tassooDao.isLoaded()) {
					return ValidationStatus.error("A Task Store has not been loaded");
				} else {
					String taskName = (String) value;
					if (StringUtils.isBlank(taskName)) {
						return ValidationStatus.error("A name for the task is required.");
					}
				}
				return ValidationStatus.ok();
			}
		});
		bindingContext.bindValue(taskNameObserveTextObserveWidget, newTaskModelTaskNameObserveValue, taskNameStrategy, null);
		//
		IObservableValue taskSummaryObserveTextObserveWidget = SWTObservables.observeText(taskSummary, SWT.Modify);
		IObservableValue newTaskModelTaskSummaryObserveValue = PojoObservables.observeValue(newTaskModel, "taskSummary");
		UpdateValueStrategy taskSummaryStrategy = new UpdateValueStrategy();
		taskSummaryStrategy.setBeforeSetValidator(new IValidator() {
			public IStatus validate(Object value) {
				if (tassooDao.isLoaded()) {
					String taskSummary = (String) value;
					if (StringUtils.isBlank(taskSummary)) {
						return ValidationStatus.error("A summary for the task is required.");
					}
				} else {
					return ValidationStatus.error("A Task Store has not been loaded");
				}
				return ValidationStatus.ok();
			}
		});
		bindingContext.bindValue(taskSummaryObserveTextObserveWidget, newTaskModelTaskSummaryObserveValue, taskSummaryStrategy,
				null);
		//
		IObservableValue txtContainerObserveTextObserveWidget = SWTObservables.observeText(txtContainer, SWT.Modify);
		IObservableValue newTaskModelContainerObserveValue = PojoObservables.observeValue(newTaskModel, "container");
		UpdateValueStrategy containerValueStrategy = new UpdateValueStrategy();
		containerValueStrategy.setBeforeSetValidator(new IValidator() {
			public IStatus validate(Object value) {
				if (tassooDao.isLoaded()) {
					String container = (String) value;
					if (StringUtils.isBlank(container)) {
						return ValidationStatus.error("A container is a required field");
					}
				} else {
					return ValidationStatus.error("A Task Store has not been loaded");
				}
				return ValidationStatus.ok();
			}
		});
		bindingContext.bindValue(txtContainerObserveTextObserveWidget, newTaskModelContainerObserveValue, containerValueStrategy,
				null);
		//
		final IObservableValue btnSubTaskObserveSelectionObserveWidget = SWTObservables.observeSelection(btnSubTask);
		final IObservableValue newTaskModelSubTaskObserveValue = PojoObservables.observeValue(newTaskModel, "subTask");
		bindingContext.bindValue(btnSubTaskObserveSelectionObserveWidget, newTaskModelSubTaskObserveValue, null, null);
		//
		final IObservableValue txtParentObserveTextObserveWidget = SWTObservables.observeText(txtParent, SWT.Modify);
		final IObservableValue newTaskModelParentTaskObserveValue = PojoObservables.observeValue(newTaskModel, "parentTask");
		bindingContext.bindValue(txtParentObserveTextObserveWidget, newTaskModelParentTaskObserveValue, null, null);
		//
		IObservableValue cmbCategoryObserveSelectionObserveWidget = SWTObservables.observeSelection(cmbCategory);
		IObservableValue newTaskModelCategoryObserveValue = PojoObservables.observeValue(newTaskModel, "category");
		bindingContext.bindValue(cmbCategoryObserveSelectionObserveWidget, newTaskModelCategoryObserveValue, null, null);
		//
		IObservableValue cmbPriorityObserveSelectionObserveWidget = SWTObservables.observeSelection(cmbPriority);
		IObservableValue newTaskModelPriorityObserveValue = PojoObservables.observeValue(newTaskModel, "priority");
		bindingContext.bindValue(cmbPriorityObserveSelectionObserveWidget, newTaskModelPriorityObserveValue, null, null);
		//
		IObservableValue cmbTypeObserveSelectionObserveWidget = SWTObservables.observeSelection(cmbType);
		IObservableValue newTaskModelTypeObserveValue = PojoObservables.observeValue(newTaskModel, "type");
		bindingContext.bindValue(cmbTypeObserveSelectionObserveWidget, newTaskModelTypeObserveValue, null, null);
		//
		IObservableValue cmbStatusObserveSelectionObserveWidget = SWTObservables.observeSelection(cmbStatus);
		IObservableValue newTaskModelStatusObserveValue = PojoObservables.observeValue(newTaskModel, "status");
		bindingContext.bindValue(cmbStatusObserveSelectionObserveWidget, newTaskModelStatusObserveValue, null, null);
		//
		IObservableValue startDateObserveWidget = new CalendarComboWidgetValueProperty().observe(cmbStartDate);
		IObservableValue startDateObserveValue = BeanProperties.value(NewTaskModel.class, "startDate").observe(newTaskModel);
		bindingContext.bindValue(startDateObserveWidget, startDateObserveValue, null, null);
		//
		IObservableValue dueDateObserveWidget = new CalendarComboWidgetValueProperty().observe(cmbDueDate);
		IObservableValue dueDateObserveValue = BeanProperties.value(NewTaskModel.class, "dueDate").observe(newTaskModel);
		bindingContext.bindValue(dueDateObserveWidget, dueDateObserveValue, null, null);
		//
		IObservableValue estimatedTimeTextObserveWidget = new TimeTextWidgetValueProperty().observe(txtEstimatedTime);
		IObservableValue estimatedTimeTextObserveValue = BeanProperties.value(NewTaskModel.class, "estimatedTime").observe(
				newTaskModel);
		bindingContext.bindValue(estimatedTimeTextObserveWidget, estimatedTimeTextObserveValue, null, null);
		//

		MultiValidator multiValidator = new MultiValidator() {
			protected IStatus validate() {
				if (tassooDao.isLoaded()) {
					if ((Boolean) btnSubTaskObserveSelectionObserveWidget.getValue()) {
						if (StringUtils.isBlank((String) txtParentObserveTextObserveWidget.getValue())) {
							return ValidationStatus.error("A parent task must be selected to be a sub task");
						}
					}
				} else {
					return ValidationStatus.error("A Task Store has not been loaded");
				}
				return ValidationStatus.ok();
			}
		};
		bindingContext.addValidationStatusProvider(multiValidator);

		return bindingContext;
	}

}
